package com.platform.data.handle;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.platform.data.common.CommonConstant;
import com.platform.data.handle.converter.DataTypeEnum;
import com.platform.data.handle.converter.DefaultStringConverter;
import com.platform.data.model.ReadDataModel;
import com.platform.data.utils.ObjectUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 解析Excel文件读的监听器
 *
 * @author weijun.zhu
 * @date 2025/5/10 13:01
 */
public class ExcelDataListener extends AnalysisEventListener<Map<Integer, String>> {
    private static final Logger log = LoggerFactory.getLogger(ExcelDataListener.class);

    /**
     * 匹配表头，属性名称
     */
    private static final Pattern fieldNamePattern = Pattern.compile(CommonConstant.FIELD_NAME_REGEX);
    /**
     * 匹配表头，子节点属性名称
     */
    private static final Pattern childNodePattern = Pattern.compile(CommonConstant.CHILD_NODE_NAME_REGEX);

    /**
     * 默认转换器
     */
    private DefaultStringConverter defaultConverter = new DefaultStringConverter();

    /**
     * 收集表头中字段名称
     */
    private final Map<Integer, String> fieldNameMap = new HashMap<>();

    /**
     * 属性数据类型
     */
    private final Map<Integer, DataTypeEnum> fieldDataTypeMap = new HashMap<>();

    /**
     * 表内容数据
     */
    private final ReadDataModel data;

    public ExcelDataListener(ReadDataModel dataModel) {
        this.data = dataModel;
    }

    /**
     * 读取表头内容
     *
     * @param headMap headMap
     * @param context context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        ReadSheetHolder sheetHolder = context.readSheetHolder();
        String sheetName = sheetHolder.getSheetName();
        Integer sheetNo = sheetHolder.getSheetNo();
        //log.info("ExcelDataListener.invokeHeadMap|正在读取[{}]Sheet表头", sheetName);

        // 设置默认电站信息属性名称
        this.data.setFieldName(CommonConstant.DEFAULT_STATION_NAME);
        // 从对应Sheet页获取属性名称
        Matcher sheetMatcher = fieldNamePattern.matcher(sheetName);
        if(sheetMatcher.find()){
           this.data.setFieldName(sheetMatcher.group().trim());
        }

        // 是否有字节点属性名称
        boolean childNodeFlag = false;
        List<String> titleNameList = new ArrayList<>();
        for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
            Integer index = entry.getKey();
            String value = entry.getValue();
            if(StringUtils.isBlank(value)){
                continue;
            }

            Matcher matcher = fieldNamePattern.matcher(value);
            if(!matcher.find()) {
                matcher = childNodePattern.matcher(value);
                if(!matcher.find()){
                    log.warn("ExcelDataListener.invokeHeadMap|正在读取[{}]Sheet表头，未获取该列属性名称，第{}列，内容：{}",
                            sheetName, index, value);
                    continue;
                } else {
                    childNodeFlag = true;
                }
            }
            String name = childNodeFlag ? matcher.group(CommonConstant.ONE).trim() : matcher.group().trim();
            String fieldName = name;
            if(name.contains(CommonConstant.COMMA_EH_CHARACTER)){
                String[] split = name.split(CommonConstant.COMMA_EH_CHARACTER);
                if(split.length > CommonConstant.ZERO){
                    fieldName = split[CommonConstant.ZERO];
                }
                if(split.length > CommonConstant.ONE){
                    String dataType = split[CommonConstant.ONE];
                    DataTypeEnum typeEnum = DataTypeEnum.getEnum(dataType);
                    if(Objects.nonNull(typeEnum)){
                        fieldDataTypeMap.put(index, typeEnum);
                    } else {
                        log.warn("ExcelDataListener.invokeHeadMap|正在读取[{}]Sheet表头，属性数据类型未定义，属性名称：{}，类型标识：{}", sheetName, fieldName, dataType);
                    }
                }
            }
            fieldNameMap.put(index, fieldName);
            titleNameList.add(fieldName);
            if(childNodeFlag){
                this.data.setChildNodeName(fieldName);
            }
            if(Objects.equals(sheetNo, CommonConstant.ZERO)){
                if(Objects.equals(index, CommonConstant.ZERO)){
                    this.data.setUniqueFieldName(fieldName);
                }
            } else {
                if(Objects.equals(index, CommonConstant.ONE)){
                    this.data.setUniqueFieldName(fieldName);
                }
            }
        }
        this.data.setFieldNameList(titleNameList);
        log.info("ExcelDataListener.invokeHeadMap|正在读取[{}]Sheet表头属性名称完成，属性名称：{}", sheetName, ObjectUtil.objToStr(titleNameList));
    }

    /**
     * 解析文件数据
     *
     * @param dataMap dataMap
     * @param context context
     */
    @Override
    public void invoke(Map<Integer, String> dataMap, AnalysisContext context) {
        ReadSheetHolder sheetHolder = context.readSheetHolder();
        String sheetName = sheetHolder.getSheetName();
        //log.info("ExcelDataListener.invoke|正在读取[{}]Sheet行内容：{}", sheetName, ObjectUtil.objToStr(dataMap));

        Map<String, Object> fieldMap = new HashMap<>();
        for (Map.Entry<Integer, String> entry : fieldNameMap.entrySet()) {
            Integer index = entry.getKey();
            String fieldName = entry.getValue();

            // 数据类型
            DataTypeEnum typeEnum = fieldDataTypeMap.get(index);
            Object fieldValue = defaultConverter.convertToData(fieldName, typeEnum, dataMap.get(index));
            fieldMap.put(fieldName, fieldValue);
        }
        if(!fieldMap.isEmpty()){
            //log.info("ExcelDataListener.invoke|正在读取[{}]Sheet行数据，转换后内容：{}", sheetName, ObjectUtil.objToStr(fieldMap));
            this.data.getDataList().add(fieldMap);
        }
    }

    /**
     * 解析数据完成
     *
     * @param context context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        ReadSheetHolder sheetHolder = context.readSheetHolder();
        log.info("ExcelDataListener.doAfterAllAnalysed|已完成[{}]Sheet内容读取", sheetHolder.getSheetName());
    }

    /**
     * 数据转换异常
     *  这里不抛出异常，继续执行后面数据解析
     *
     * @param exception exception
     * @param context context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        super.onException(exception, context);
    }
}
